#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

#define SIZE 1024
char CommandLine[SIZE];  //存放输入的指令

#define OPT_NUM 64
char* Myargv[OPT_NUM];  //存放分割后的程序指令

//保存上次运行时的退出码和退出信号
int lastCode;
int lastSignal;

int main( )
{
  while(true)
  {
    //1.打印提示符
    printf("[用户名@主机名 当前路径]#");
    fflush(stdout);        //刷新缓冲区

    //获取用户输入
    char* s = fgets(CommandLine,sizeof(CommandLine)-1,stdin);
    assert(s != NULL);  //检查释放获取成功
    (void)s;      
    CommandLine[strlen(CommandLine)-1] = 0;  //消除掉输入时带的换行符
    //字符串分割，拿出指令

    Myargv[0] = strtok(CommandLine," ");
    int i = 1;
    //给ls命令增加配色方案
    if(Myargv[0]!=NULL && strcmp(Myargv[0],"ls")==0)
    {
      Myargv[i++] = (char*)"--color=auto";
    }
    while( Myargv[i++] = strtok(NULL," "));  //无法分割时返回空指针。 命令行参数最后刚好需要以NULL结尾

    //内建命令，内置命令不需要创建子进程来执行
    //cd 命令需要改变当前进程的工作目录
    if(Myargv[0]!=NULL && strcmp(Myargv[0],"cd")==0)
    {
        if(Myargv[1]!=NULL)
        chdir(Myargv[1]);
        continue;
    }

    //echo命令获取上次程序的退出码
    if(Myargv[0]!=NULL && Myargv[1]!=NULL && strcmp(Myargv[0],"echo")==0)
    {
        if(strcmp(Myargv[1],"$?")==0)
        {
          printf("lastcode:%d , lastSignal:%d\n",lastCode,lastSignal);
        }
        else
        {
          printf("%s\n",Myargv[1]);
        }
        continue;
    }

//条件编译来测试  编译时带上 -DDEBUG即可运行测试
#ifdef DEBUG
for(int i=0; Myargv[i] ;++i)
printf("%s\n",Myargv[i]);
#endif

 //创建子进程执行相关指令
pid_t id = fork();
assert(id != -1); //检测子进程是否创建失败

if(id == 0) //子进程进程切换 执行对应的指令
{
  execvp(Myargv[0],Myargv);

  exit(1); //异常时才从这退出
}
int status;  //拿到子程序的退出码
waitpid(id,&status,0);

lastCode = ((status>>8) & 0xFF);
lastSignal = (status & 0x7F);
    
 }
  return 0;
}
